// -*- C++ -*-
//
//  This file is part of Siena, a wide-area event notification system.
//  See http://www.inf.usi.ch/carzaniga/siena/
//
//  Authors: Antonio Carzaniga
//  See the file AUTHORS for full details. 
//
//  Copyright (C) 2001-2002 University of Colorado
//
//  This program is free software; you can redistribute it and/or
//  modify it under the terms of the GNU General Public License
//  as published by the Free Software Foundation; either version 2
//  of the License, or (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
//  USA, or send email to one of the authors.
//
//
// $Id: forwarding.h,v 1.20 2010-03-11 15:16:45 carzanig Exp $
//
#ifndef SIENA_FORWARDING_H
#define SIENA_FORWARDING_H

#include <cstddef>
#include <new>

#include "exceptions.h"
#include "types.h"
#include "stst.h"
#include "allocator.h"

/** \file forwarding.h 
 *
 *  This header file defines Siena's forwarding module interface.
 **/

namespace siena {

/** @brief Interface type.  
 *
 *  For simplicity, an interface is represented by a number.  This is
 *  an explicit design choice.  More information can be associated
 *  with an interface through a secondary data structure (a vector or
 *  anything else).
 **/
typedef unsigned int		if_t;

/** @brief inteface identifier within the matching algorithm.  
 *
 *  As opposed to <code>if_t</code> which identifies user-specified
 *  interface numbers, this is going to be used for the identification
 *  of interfaces within the matching algorithm, which may require a
 *  set of contiguous identifiers.  So, for example, the user may
 *  specify interfaces 6, 78, and 200, while the internal
 *  identification would be 0, 1, and 2 respectively (or similar).  I
 *  treat it as a different type (from <code>if_t</code>) because I
 *  don't want to mix them up (now that I write this, I'm not even
 *  sure the compiler would complain. Oh well.)
 **/
typedef unsigned int		ifid_t;

/** @brief hook for the output function for matching interfaces.
 *
 *  The matching function of the forwarding table doesn't actually
 *  produce an output.  Instead, it delegates the processing of
 *  matching interfaces to a specialized <em>match handler</em>.  This
 *  base class defines the interface of such a handler.  Users of the
 *  forwarding table must implement this interface and pass it to the
 *  matching function.
 *
 *  <p>The \link forwarding_messages.cc forwarding_messages\endlink
 *  example shows how to set up and use match handlers.  
 *
 *  \see MatchMessageHandler
 **/
class MatchHandler {
public:
    /** @brief virtual destructor */
    virtual		~MatchHandler() {};

    /** @brief output function.
     *
     *  This function is called within the \link siena::ForwardingTable::match(const message &, MatchHandler &) const matching function\endlink
     *  of the forwarding table.  The parameter is the interface
     *  identifier of the matching interface.  This function may
     *  explicitly cause the matching function to terminate by
     *  returning true. 
     **/
    virtual bool	output(if_t) throw() = 0;
};

/** @brief hook for the output function for matching interfaces.
 *
 *  The matching function of the forwarding table doesn't actually
 *  produce any output.  Instead, it delegates the processing of
 *  matching interfaces to a specialized <em>match handler</em>.  This
 *  base class defines the interface of such a handler.  Users of the
 *  forwarding table must implement this interface and pass it to the
 *  matching function.
 *
 *  \see MatchHandler
 **/
class MatchMessageHandler {
public:
    /** @brief virtual destructor */
    virtual		~MatchMessageHandler() {};

    /** @brief output function.
     *
     *  This function is called within the 
     *  \link siena::ForwardingTable::match(const message &, MatchMessageHandler &) const throw()
     *  matching function\endlink of the forwarding table.  This
     *  method is given the interface identifier of the matching
     *  interface and a reference to the matching message.  This
     *  function may explicitly cause the matching function to
     *  terminate by returning true.
     **/
    virtual bool	output(if_t, const message &) throw() = 0;
};


/** @brief The heart of the forwarding table. 
 *
 *  A <code>ForwardingTable</code> associates predicates to interfaces.  A
 *  Predicate is a disjunction of conjunctions of elementary
 *  constraints.  An interface is simply an identifier, corresponding
 *  to the link-level address of a neighbor.
 *
 *  The forwarding table is a \em dictionary data structure,
 *  meaning that the set of associations that it represents can
 *  constructed by adding associations, but can not be modified by
 *  removing or modifying individual associations.  In order to modify
 *  individual associations, the forwarding table must be completely
 *  cleared, using the \link clear() clear\endlink or 
 *  \link clear_recycle() clear_recycle \endlink methods, and built over
 *  again.
 *
 *  More specifically, the forwarding table operates in two modes.  
 *  Initially the
 *  forwarding table is in <em>configuration mode</em>.  While in 
 *  configuration mode, the forwarding table can be configured by 
 *  associating predicates to interfaces using the 
 *  \link siena::ForwardingTable::ifconfig() ifconfig\endlink method.  
 *  Once all the interfaces have been associated with their predicate,
 *  the forwarding table must be prepared for matching by calling the 
 *  \link siena::ForwardingTable::consolidate() consolidate\endlink method.
 *  The consolidate method switches the forwarding table to
 *  <em>matching mode</em>, which means that the forwarding table can
 *  be used to match messages.  The forwarding table, can then be
 *  cleared and restored to configuration mode with the 
 *  \link siena::ForwardingTable::clear() clear\endlink or 
 *  \link siena::ForwardingTable::clear_recycle() clear_recycle\endlink methods. 
 *
 *  Once in matching mode, the forwarding table can match incoming
 *  messages with the \link siena::ForwardingTable::match() match\endlink
 *  method.  The forwarding table delegates the processing of matched
 *  notifications to a given \em handler.  Two classes of handlers are
 *  supported: MatchMessageHandler, which uses an output function that
 *  takes an interface identifier and a message, and MatchHandler,
 *  which uses an output function that takes an interface identifier
 *  only.
 * 
 *  The forwarding table manages its memory allocation through a
 *  dedicated block-allocator.  When cleared with clear(), the
 *  forwarding table releases all the previously allocated memory.
 *  clear_recycle() can be used to clear the forwarding table and
 *  recycle previously allocated memory.  In this latter case,
 *  previously allocated memory is saved for future use.
 **/
class ForwardingTable {
public:
    /** @brief Destroys the forwarding including all its internal data
     *  structures.
     **/
    virtual		~ForwardingTable() throw() {};

    /** @brief Associates a predicate to an interface.
     *
     *  This is the method that constructs the forwarding table.  This
     *  method must be called \em once for each interface, after
     *  the forwarding table is constructed or after it has been
     *  cleared.  Using this method twice on the same interface
     *  without clearing the forwarding table has undefined effects.
     *
     *  @see consolidate()
     **/
    virtual void	ifconfig(if_t, const predicate &) throw(bad_constraint, std::bad_alloc) = 0;
    /** @brief Prepares the forwarding table for matching.
     *
     *  This function processes the forwarding table, packing some of
     *  its internal data structures and preparing them to be used to
     *  match events.  This function must therefore be called after
     *  all the necessary calls to \link ifconfig() ifconfig\endlink
     *  and before matching messages with 
     *  \link match(const message &, MatchHandler &) const match()\endlink.
     *  <p>The forwarding table can be reset by calling 
     *  \link clear() clear\endlink or 
     *  \link clear_recycle() clear_recycle\endlink.
     *
     *  @see clear()
     *  @see recycle_clear()
     **/
    virtual void	consolidate() throw() {};

    /** @brief Processes a message, calling the output() function on
     *	the given MatchHandler object for each matching interface.
     *
     *  Matches a message against the predicates stored in the
     *  forwarding table.  The result is processed through the
     *  MatchHandler passed as a parameter to this function.
     *
     *  Notice that the forwarding table must be consolidated by
     *  calling \link siena::ForwardingTable::consolidate()\endlink
     *  before this function is called.
     *
     *  @see consolidate()
     **/
    virtual void	match(const message &, MatchHandler &) const 
	throw() = 0;

    /** @brief Processes a message, calling the output() function on
     *	the given MatchMessageHandler object for each matching
     *	interface.
     *
     *  @see consolidate()
     *  @see ifconfig()
     **/
    virtual void	match(const message &, MatchMessageHandler &) const 
	throw() = 0;

    /** @brief Clears the forwarding table.
     *
     *  This method removes all the associations from the forwarding
     *  table and releases allocated memory.  After a call to this
     *  method, the forwarding table is ready to be configured with
     *  \link ifconfig()\endlink.
     *
     *  @see ifconfig()
     *  @see consolidate()
     **/
    virtual void	clear() throw() = 0;

    /** @brief Clears the forwarding table.
     *
     *  This method removes all the associations from the forwarding
     *  table recycling the allocated memory. After a call to this
     *  method, the forwarding table is ready to be configured with
     *  \link ifconfig()\endlink.
     *
     *  @see ifconfig()
     *  @see consolidate()
     **/
    virtual void	clear_recycle() throw() = 0;

    /** @brief Memory allocated by the forwarding table.
     *
     *  returns the number of bytes of memory allocated by the
     *  forwarding table.  This value is always greater than or equal
     *  to the value returned by bytesize().
     **/
    virtual size_t	allocated_bytesize() const throw() = 0;

    /** @brief Memory used by the forwarding table.
     *
     *  returns the number of bytes of memory used by the forwarding
     *  table.  This value is always less than or equal to the value
     *  returned by allocated_bytesize().
     **/
    virtual size_t	bytesize() const throw() = 0;
};

} // end namespace siena

//
// for source-level compatibility, we also include fwdtable.h here
//
#include "fwdtable.h"

#endif
